unit ICore.Threads;

interface
uses Windows;

{$DEFINE WINDOWS}

type
//  TRTLCriticalSection = array [0..5] of LongWord;
  TThreadProc = procedure (Param: Pointer); stdcall;

type
{$REGION 'TThread = class'}
  TThread = class
    constructor Create(const Proc: TThreadProc; const Param: Pointer; const Activate: Boolean = True);
    destructor Destroy; override;
  private
    FActive:  Boolean;
    FDone:    Boolean;
    FProc:    TThreadProc;
    FParam:   Pointer;
    FHandle:  LongWord;
    procedure SetActive(const Value: Boolean);
    procedure SetCPUMask(const Value: LongInt);
  public
    procedure Wait; overload;
    procedure Wait(const ms: LongWord{ = 0}); overload;
    property CPUMask: LongInt write SetCPUMask;
    property Active: Boolean write SetActive;
    property Done: Boolean read FDone;
  end;
{$ENDREGION}

{$REGION 'TCriticalSection = object'}
  TCriticalSection = object
  private
    FCriticalSection: TRTLCriticalSection;
  public
    procedure Init;
    procedure Free;
    procedure Enter;
    procedure Leave;
    property CriticalSection: TRTLCriticalSection read FCriticalSection;
  end;
{$ENDREGION}

{$REGION 'TThreadInfo = record'}
  TThreadInfo = record
    Thread: ^TThread;
    Proc:   TThreadProc;
    Param:  Pointer;
  end;
{$ENDREGION}

implementation

{$REGION 'TThread'}
procedure ThreadProc(var Thread: TThread); stdcall;
begin
  Thread.FProc(Thread.FParam);
  Thread.FDone := True;
end;

constructor TThread.Create(const Proc: TThreadProc; const Param: Pointer; const Activate: Boolean = True);
var
  Flag: LongWord;
begin
  inherited Create;
  FActive := Activate;

  if FActive then
   Flag := 0
  else
   Flag := 4;//create_suspended
  FDone := False;
  FProc := Proc;
  FParam := Param;
  FHandle := CreateThread(nil, 0, @ThreadProc, Pointer(Self), Flag, LongWord(nil^));
end;

destructor TThread.Destroy;
begin
  TerminateThread(FHandle, 0);
  inherited;
end;

procedure TThread.SetActive(const Value: Boolean);
begin
  if FActive <> Value then begin
    FActive := Value;

    if Value then
     ResumeThread(FHandle)
    else
     SuspendThread(FHandle);
  end;
end;

procedure TThread.SetCPUMask(const Value: Integer);
begin
  FDone := True;
  SetThreadAffinityMask(FHandle, Value);
end;

procedure TThread.Wait;
begin
  WaitForSingleObject(FHandle, INFINITE);
end;

procedure TThread.Wait(const ms: Cardinal{ = 0});
begin
//  Sleep(ms);
  WaitForSingleObject(FHandle, ms);
end;
{$ENDREGION}

{$REGION 'TCriticalSection'}
procedure TCriticalSection.Init;
begin
  InitializeCriticalSection(FCriticalSection);
end;

procedure TCriticalSection.Free;
begin
  DeleteCriticalSection(FCriticalSection);
end;

procedure TCriticalSection.Enter;
begin
  EnterCriticalSection(FCriticalSection);
end;

procedure TCriticalSection.Leave;
begin
  LeaveCriticalSection(FCriticalSection);
end;
{$ENDREGION}

end.
